namespace Aob.Lite

import System

import Boo.Lang.Compiler
import Boo.Lang.Compiler.Ast
import Boo.Lang.Compiler.TypeSystem

class AdviceTransformer(DepthFirstVisitor):
"""Description of AdviceTransformer"""
	_context as CompilerContext
	_pointcutIMethod as IMethod
	_adviceIMethod as IMethod
	_adviceMethod as Method
	_currentClassDef as ClassDefinition
	
	def constructor(
				[required] context as CompilerContext,
				[required] pointcutIMethod as IMethod,
				[required] adviceIMethod as IMethod, 
				[required] adviceMethod as Method):
		_context = context
		_pointcutIMethod = pointcutIMethod
		_adviceIMethod = adviceIMethod
		_adviceMethod = adviceMethod
		
	override def EnterMethod(node as Method):
		super(node)
		_currentClassDef = node.DeclaringType
		return true
		
	override def LeaveMethodInvocationExpression(invocation as MethodInvocationExpression):
		return if _pointcutIMethod is not GetEntity(invocation.Target)
		InsertPointcutExtension()
		ReplacePointcutCall()
		super(invocation)
		
	def GetEntity(node as Node):
		return TypeSystemServices.GetOptionalEntity(node)
		
	def InsertPointcutExtension():
		module = GetModuleForClassDef()
//		module.Members.Add(CreatePointcutExtension())
		
	def GetModuleForClassDef():
		parent as Node = _currentClassDef
		while not parent isa Module:
			parent = parent.ParentNode
		return (parent as Module)
		
	def CreatePointcutExtension():
		name = FormatPointcutWrapperName(_pointcutIMethod.FullName)
		method = _context.CodeBuilder.CreateMethod(name,
									_context.CodeBuilder.TypeSystemServices.VoidType,
									TypeMemberModifiers.Static)
		method.Body.Add(Ast.ReturnStatement())
		Dsl.m(method)
		return method

	def ReplacePointcutCall():
		pass
		// this is the most simple way of doing it
		//invocation.Target = _context.CodeBuilder.CreateReference(wrapper)

	def CreatePointcutCallWrapper():
		method = _context.CodeBuilder.CreateMethodFromPrototype(LexicalInfo("Advice generated"), _pointcutIMethod, TypeMemberModifiers.Final)
		method.Name = FormatPointcutWrapperName(_pointcutIMethod.FullName)
		_currentClassDef.Members.Add(method)
		return method
		
	private def FormatPointcutWrapperName(name as string):
		return "${name.Replace(char('.'), char('_'))}CallWrapper"
	
/*		
	override def EnterMethod(node as Method):
		if _pointcutIMethod is not GetEntity(node): return
		CreateInternalMethod(node)
		RewritePointcut(node)

		super(node)
				
	def CreateInternalMethod(node as Method):
		newMethod as Method = node.Clone()
		newMethod.Name = "__${newMethod.Name}_Internal__"
		GetEnclosingTypeDefinition(_pointcutIMethod).Members.Add(newMethod)

	def RewritePointcut(node as Method):
		node.Body.Clear()
		jp = ast { j = AopLite.Jointpoint() }
		node.Body.Add(jp)

	def InsertAdvice(node as MethodInvocationExpression):
		newMethod = CopyMethod()
		GetEnclosingTypeDefinition(_pointcutIMethod).Members.Add(newMethod)
		return newMethod
	
	def CopyMethod():
		newMethod = _context.CodeBuilder.CreateMethodFromPrototype(
					LexicalInfo("advice generated"), 
					_pointcutIMethod, 
					TypeMemberModifiers.Internal)
		
		newMethod.Name = "__${newMethod.Name}_Advice__"
		newMethod.Body = (_pointcutIMethod as Method).Body.Clone()
		return newMethod

	def GetEnclosingTypeDefinition(member as IMember):
		return (member.DeclaringType as IInternalEntity).Node as TypeDefinition
		
	def GetEntity(node as Node):
		return TypeSystemServices.GetOptionalEntity(node)
*/

